﻿using System;
using System.Collections.Generic;
using System.Windows.Automation;
using QuickUIT.Utilities;

namespace QuickUIT.Controls
{
    /// <summary>
    /// Represents a tree control. 
    /// </summary>
    public class UITree : UIBaseControl
    {
        /// <summary>
        /// Gets a value which indicates whether the control can scroll horizontally. 
        /// </summary>
        public new bool HorizontallyScrollable
        {
            get { return base.HorizontallyScrollable; }
        }

        /// <summary>
        /// Gets a value which indicates whether the control can scroll horizontally. 
        /// </summary>
        public new bool VerticallyScrollable
        {
            get { return base.VerticallyScrollable; }
        }

        /// <summary>
        /// Gets the value of the horizontal scroll position.
        /// If the control does not support the <see cref="ScrollPattern"/>, returns NaN. 
        /// </summary>
        public new double HorizontalScrollPercent
        {
            get { return base.HorizontalScrollPercent; }
        }

        /// <summary>
        /// Gets the value of the vertical scroll position 
        /// If the control does not support the <see cref="ScrollPattern"/>, returns NaN.
        /// </summary>
        public new double VerticalScrollPercent
        {
            get { return base.VerticalScrollPercent; }
        }

        /// <summary>
        /// Gets the value of the horizontal size of the viewable region.
        /// If the control does not support the <see cref="ScrollPattern"/>, returns NaN.
        /// </summary>
        public new double HorizontalViewSize
        {
            get { return base.HorizontalViewSize; }
        }

        /// <summary>
        /// Gets the value of the vertical size of the viewable region.
        /// If the control does not support the <see cref="ScrollPattern"/>, returns NaN.
        /// </summary>
        public new double VerticalViewSize
        {
            get { return base.VerticalViewSize; }
        }

        /// <summary>
        /// Gets a value that indicates whether the control requires at least one child child element to be selected. 
        /// </summary>
        public new bool IsSelectionRequired
        {
            get { return base.IsSelectionRequired; }
        }

        /// <summary>
        /// Gets a value that indicates whether the control allows more than one child element to be selected concurrently. 
        /// </summary>
        public new bool CanSelectMultiple
        {
            get { return base.CanSelectMultiple; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UITree"/> class. 
        /// </summary>
        public UITree() : base(ControlType.Tree)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UITree"/> class.
        /// </summary>
        /// <param name="parent">The parent of this control.</param>
        public UITree(UIBaseControl parent) : base(parent, ControlType.Tree)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UITree"/> class.
        /// </summary>
        /// <param name="locator">The locator used to find the specific control.</param>
        public UITree(string locator) : base(null, ControlType.Tree, locator)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UITree"/> class.
        /// </summary>
        /// <param name="parent">The parent of this control.</param>
        /// <param name="locator">The locator used to find the specific control.</param>
        public UITree(UIBaseControl parent, string locator) : base(parent, ControlType.Tree, locator)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UITree"/> class.
        /// </summary>
        /// <param name="control">The underlying <see cref="AutomationElement"/> of the control.</param>
        public UITree(AutomationElement control) : base(control, ControlType.Tree)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UITree"/> class.
        /// </summary>
        /// <param name="parent">The parent of the control</param>
        /// <param name="control">The underlying <see cref="AutomationElement"/> of the control.</param>
        public UITree(UIBaseControl parent, AutomationElement control) : base(parent, control, ControlType.Tree)
        {
        }

        /// <summary>
        /// Scrolls the visible region of the content area horizontally and vertically. 
        /// </summary>
        /// <param name="horizontalAmount">The horizontal scrolling increment that is specific to the control.</param>
        /// <param name="verticalAmount">The vertical scrolling increment that is specific to the control.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The current element does not exist anymore.</exception>
        /// <remarks>No scroll should be passed if if the control cannot be scrolled in a given direction.</remarks>
        public new void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount)
        {
            base.Scroll(horizontalAmount, verticalAmount);
        }

        /// <summary>
        /// Sets the horizontal and/or vertical scroll of the document.  
        /// </summary>
        /// <param name="horizontalPercent">
        /// The percentage of the total horizontal content area. 
        /// NoScroll should be passed in if the control cannot be scrolled in this direction.
        /// </param>
        /// <param name="verticalPercent">
        /// The percentage of the total vertical content area. 
        /// NoScroll should be passed in if the control cannot be scrolled in this direction.
        /// </param>
        public new void SetScrollPercent(double horizontalPercent, double verticalPercent)
        {
            base.SetScrollPercent(horizontalPercent, verticalPercent);
        }

        /// <summary>
        /// Scrolls the visble region of the content area vertically by a <see cref="ScrollAmount"/>.
        /// </summary>
        /// <param name="amount">The vertical scrolling increment.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        public new void ScrollVertically(ScrollAmount amount)
        {
            base.ScrollVertically(amount);
        }

        /// <summary>
        /// Scrolls the visble region of the content area horizontally by a <see cref="ScrollAmount"/>.
        /// </summary>
        /// <param name="amount">The horizontal scrolling increment.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        public new void ScrollHorizontally(ScrollAmount amount)
        {
            base.ScrollHorizontally(amount);
        }

        /// <summary>
        /// Scrolls to the top of the list control. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        public new void ScrollToTop()
        {
            base.ScrollToTop();
        }

        // TODO: support getting tree items 
        //public UITreeItem TreeItem()
        //{     // override to expand on search 
        //    return new UITreeItem(this);
        //}

        // todo: support virtualization, scrolling 
        /// <summary>
        /// Selects an item from the tree. 
        /// </summary>
        /// <param name="names">The path to the tree item to select.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        public void SelectItem(string[] names)
        {
            ValidationUtility.ValidateArgumentNotNull(names, "names");

            if (names.Length == 0)
            {
                return; 
            }

            AutomationElement foundTreeItem = Control; 
            var treeItemNames = new Queue<string>(names);
            while (treeItemNames.Count != 0)
            {
                string name = treeItemNames.Dequeue();
                var criteria = new AutomationElementSearchCriteria();
                criteria.Add(new AutomationElementExactSearchCondition(AutomationElementIdentifiers.NameProperty, name));
                var treeItem = AutomationElementFinder.FindFirst(foundTreeItem, criteria);
                if (treeItem == null)
                {
                    throw new InvalidOperationException(String.Format("The tree item '{0}' was not found.", name));
                }

                // Scroll tree item into view 
                var scrollPattern = AutomationElementPatterns.GetPattern<ScrollItemPattern>(treeItem,
                                                                                            ScrollItemPattern.Pattern);
                if (scrollPattern != null)
                {
                    scrollPattern.ScrollIntoView();
                }

                // Expand tree items 
                var expandPattern = AutomationElementPatterns.GetPattern<ExpandCollapsePattern>(treeItem,
                                                                                                ExpandCollapsePattern
                                                                                                    .Pattern);
                if (expandPattern != null &&
                    expandPattern.Current.ExpandCollapseState ==
                    System.Windows.Automation.ExpandCollapseState.Collapsed)
                {
                    expandPattern.Expand();
                }
                foundTreeItem = treeItem; 
            }

            AutomationElementPatterns.Select(foundTreeItem);
        }

        /// <summary>
        /// Gets the current selection for this tree control. 
        /// </summary>
        /// <returns>Automation element of the current selected tree item. Nothing if there is no selected item.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        public AutomationElement GetSelectedItem()
        {
            WaitForParentWindowToBeReady();
            var selection = AutomationElementPatterns.GetSelection(Control);
            return selection.Length == 0 ? null : selection[0];
        }

        /// <summary>
        /// Gets a collection of elements that represents the current selection for an element.
        /// </summary>
        /// <returns>A collection of selected elements.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        public new AutomationElement[] GetSelection()
        {
            return base.GetSelection();
        }
    }
}
